package org.apache.ibatis.session;

import org.apache.ibatis.configuration.CommandType;
import org.apache.ibatis.configuration.Configuration;
import org.apache.ibatis.configuration.MappedStatement;
import org.apache.ibatis.executor.SimpleExecutor;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map;

/**
 * @Classname DefaultSqlSession
 * @Description SqlSession的默认实现
 * @Date 2025/1/16 12:57
 * @Author zhuzhenguo
 */
public class DefaultSqlSession implements SqlSession {

    /**
     * 封装的是我们的配置信息
     */
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        // simpleExecutor Query方法完成查询
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        return (List<E>) list;
    }

    @Override
    public <E> E selectOne(String statementId, Object... params) throws Exception {
        List<Object> objects = this.selectList(statementId, params);
        if (objects.size() == 1) {
            return (E) objects.get(0);
        } else {
            throw new RuntimeException("查询结果不唯一或为空");
        }
    }

    @Override
    public <E> E insert(String statementId, Object... params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        if (list.size() > 0) {
            return (E) list.get(0);
        } else {
            return (E) "0";
        }
    }

    @Override
    public <E> E update(String statementId, Object... params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        if (list.size() > 0) {
            return (E) list.get(0);
        } else {
            return (E) "0";
        }
    }

    @Override
    public <E> E delete(String statementId, Object... params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = this.configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        if (list.size() > 0) {
            return (E) list.get(0);
        } else {
            return (E) "0";
        }
    }

    /**
     * 使用JDK动态代理给xxxMapper接口创建代理对象
     * todo JDK动态代理
     *
     * @param mapperClass 字节码
     * @return {@link T}
     * @throws Exception 例外
     */
    @Override
    public <T> T getMapper(Class<T> mapperClass) throws Exception {
        // 使用JDK动态代理给xxxMapper接口创建代理类对象，其实就是实现类
        Object instance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 在匿名内部类中，完成接口的实现
                // 接口中的方法名
                String methodName = method.getName();
                // 接口的全类名
                String className = method.getDeclaringClass().getName();
                // 拼接SQL的唯一标识
                String statementId = className + "." + methodName;
                // 获取方法被调用后的返回值类型
                Type genericReturnType = method.getGenericReturnType();
                Map<String, MappedStatement> mappedStatementMap = configuration.getMappedStatementMap();
                MappedStatement mappedStatement = mappedStatementMap.get(statementId);
                if ("insert".equals(mappedStatement.getSqlType())) {
                    // JDBC底层增删改都是一样的
                    return insert(statementId, args);
                } else if ("update".equals(mappedStatement.getSqlType())) {
                    return update(statementId, args);
                } else if ("delete".equals(mappedStatement.getSqlType())) {
                    return delete(statementId, args);
                }

                // 判断是否进行了泛型类型的参数化(返回结果是泛型的化查询集合)
                if (genericReturnType instanceof ParameterizedType) {
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                } else {
                    // 查询的结果里不戴泛型的话，就直接返回对象
                    return selectOne(statementId, args);
                }
            }
        });
        return (T) instance;
    }
}
